import {
	DPI,
	S10,
	S5,
	getYSpace,
} from './utils.js';
/**
 * 图表类
 * @param {String} canvas 画布元素id
 * @param {Object} options 图表参数 可选参数
 */
class Schart {
	constructor(canvas, options) {
		let width = canvas.clientWidth;
		let height = canvas.clientHeight; 
		canvas.width = width * DPI;
		canvas.height = height * DPI;
		this.canvas = canvas;
		this.ctx = this.canvas.getContext('2d');
		this.type = 'bar';
		this.showValue = true; // 是否在图表中显示数值
		this.showGrid = true; // 是否显示网格
		this.topPadding = 60 * DPI; // 图表上边距
		this.leftPadding = 50 * DPI; // 图表左边距
		this.rightPadding = 10 * DPI; // 图表右边距
		this.bottomPadding = 50 * DPI; // 图表下边距
		this.yEqual = 5; // y轴分成5等分
		this.yLength = 0; // y轴坐标点之间的真实长度
		this.xLength = 0; // x轴坐标点之间的真实长度
		this.ySpace = 0; // y轴坐标点之间显示的间距
		this.xRorate = 0; // x轴坐标点文本旋转角度
		this.yRorate = 0; // y轴坐标点文本旋转角度
		this.bgColor = '#fff'; // 默认背景颜色
		this.axisColor = '#666'; // 坐标轴颜色
		this.gridColor = '#eee'; // 网格颜色
		this.title = { // 标题
			text: '',
			color: '#666',
			position: 'top',
			font: 'bold ' + 18 * DPI + 'px Arial',
			top: S10,
			bottom: S5
		};
		this.legend = { // 图例
			display: true,
			position: 'top',
			color: '#666',
			font: 14 * DPI + 'px Arial',
			top: 45 * DPI,
			bottom: 15 * DPI,
			textWidth: 0
		};
		this.radius = 100 * DPI; // 饼图半径和环形图外圆半径
		this.innerRadius = 60 * DPI; // 环形图内圆半径
		this.colorList = [ // 颜色列表
			'#4A90E2',
			'#F5A623',
			'#ff5858',
			'#5e64ff',
			'#2AC766',
			'#743ee2',
			'#b554ff',
			'#199475'
		];
		this.init(options);
	}

	init(options) {
		options.title = Object.assign({}, this.title, options.title);
		options.legend = Object.assign({}, this.legend, options.legend);
		Object.assign(this, options);

		if (!options.labels || !options.labels.length) {
			throw new Error('缺少主要参数labels');
		}
		if (!options.datasets || !options.datasets.length) {
			throw new Error('缺少主要参数datasets');
		}

		this.drawBackground();
		if (this.type === 'bar' || this.type === 'line') {
			this.renderBarChart();
		} else {
			this.renderPieChart();
		}
		this.drawLegend();
	}

	renderBarChart() {
		this.yLength = Math.floor((this.canvas.height - this.topPadding - this.bottomPadding - S10) / this.yEqual);
		this.xLength = Math.floor((this.canvas.width - this.leftPadding - this.rightPadding - S10) / this.labels.length);
		this.ySpace = getYSpace(this.datasets, this.yEqual);
		this.drawXAxis();
		this.drawYAxis();
		this.drawBarContent();
	}

	// 绘制柱形图和折线图内容
	drawBarContent() {
		let ctx = this.ctx;
		let length = this.datasets.length;
		ctx.beginPath();
		for (let i = 0; i < length; i++) {
			ctx.font = this.legend.font;
			// 计算图例文本长度
			this.legend.textWidth += Math.ceil(ctx.measureText(this.datasets[i].label).width);
			ctx.fillStyle = ctx.strokeStyle = this.datasets[i].fillColor || this.colorList[i];
			const item = this.datasets[i].data;

			for (let j = 0; j < item.length; j++) {
				if (j > this.labels.length - 1) {
					// 兼容数据比labels多，多的部分不显示
					continue;
				}
				let space = this.xLength / (length + 1);
				let ratio = this.yLength / this.ySpace;
				let left = this.leftPadding + this.xLength * j + space * (i + 1 / 2);
				let right = left + space;
				let bottom = this.canvas.height - this.bottomPadding;
				let top = bottom - item[j] * ratio;

				if (this.type === 'bar') {
					ctx.fillRect(
						left,
						top,
						right - left,
						bottom - top
					);
					this.drawValue(item[j], left + space / 2, top - S5);
				} else if (this.type === 'line') {
					let x = this.leftPadding + this.xLength * (j + 1 / 2);
					// 折点小圆圈
					ctx.beginPath();
					ctx.arc(x, top, 3 * DPI, 0, 2 * Math.PI, true);
					ctx.fill();
					if (j !== 0) {
						ctx.beginPath();
						ctx.strokeStyle = this.datasets[i].fillColor || this.colorList[i];
						ctx.lineWidth = 2 * DPI;
						ctx.moveTo(x - this.xLength, bottom - item[j - 1] * ratio);
						ctx.lineTo(x, top);
						ctx.stroke();
						ctx.lineWidth = 1 * DPI;
					}
					this.drawValue(item[j], x, top - S10);
				}
			}
		}
		ctx.stroke();
	}

	// 绘制饼状图和环形图
	renderPieChart() {
		let ctx = this.ctx;
		let length = this.labels.length;
		let item = this.datasets[0];
		let data = item.data;
		// 获取所有数据的总和
		let total = data.reduce((prev, current) => {
			return prev + current;
		});
		// 用于计算每块扇形弧度的起始位和终止位
		let circular = -Math.PI / 2;
		let x = this.canvas.width / 2;
		let y = this.canvas.height / 2;
		for (let i = 0; i < length; i++) {
			ctx.font = this.legend.font;
			// 计算图例文本长度
			this.legend.textWidth += Math.ceil(ctx.measureText(this.labels[i]).width);
			ctx.beginPath();

			ctx.strokeStyle = ctx.fillStyle = (item.colorList && item.colorList[i]) || this.colorList[i];
			ctx.moveTo(x, y);

			let start = circular;
			circular += data[i] / total * 2 * Math.PI;
			let end = circular;
			// 绘制扇形
			ctx.arc(x, y, this.radius, start, end);
			ctx.closePath();
			ctx.fill();
			// 绘制数据
			let middle = (start + end) / 2;
			this.drawPieValue(data[i], middle);
		}
		// 环形图在饼状图基础上再绘制一个内圆
		if (this.type === 'ring') {
			ctx.beginPath();
			ctx.fillStyle = this.bgColor;
			ctx.arc(x, y, this.innerRadius, 0, 2 * Math.PI);
			ctx.closePath();
			ctx.fill();
		}
	}

	// 绘制柱形图和折线图的数据值显示
	drawValue(value, x, y) {
		let ctx = this.ctx;
		if (!this.showValue) {
			return;
		}
		ctx.textBaseline = 'middle';
		ctx.font = 12 * DPI + 'px Arial';
		ctx.textAlign = 'center';
		ctx.fillText(value, x, y);
	}

	// 绘制饼状图和环形图的数据值显示
	drawPieValue(value, middle) {
		let ctx = this.ctx;
		if (!this.showValue) {
			return;
		}
		let x = this.canvas.width / 2;
		let y = this.canvas.height / 2;
		let x1 = Math.ceil(Math.abs(this.radius * Math.cos(middle)));
		let y1 = Math.floor(Math.abs(this.radius * Math.sin(middle)));
		ctx.textBaseline = 'middle';
		// 绘制各个扇形边上的数据
		if (this.showValue) {
			if (middle <= 0) {
				ctx.textAlign = 'left';
				ctx.moveTo(x + x1, y - y1);
				ctx.lineTo(x + x1 + S10, y - y1 - S10);
				ctx.moveTo(x + x1 + S10, y - y1 - S10);
				ctx.lineTo(x + x1 + 3 * S10, y - y1 - S10);
				ctx.stroke();
				ctx.fillText(value, x + x1 + 3.5 * S10, y - y1 - S10);
			} else if (middle > 0 && middle <= Math.PI / 2) {
				ctx.textAlign = 'left';
				ctx.moveTo(x + x1, y + y1);
				ctx.lineTo(x + x1 + S10, y + y1 + S10);
				ctx.moveTo(x + x1 + S10, y + y1 + S10);
				ctx.lineTo(x + x1 + 3 * S10, y + y1 + S10);
				ctx.stroke();
				ctx.fillText(value, x + x1 + 3.5 * S10, y + y1 + S10);
			} else if (middle > Math.PI / 2 && middle < Math.PI) {
				ctx.textAlign = 'right';
				ctx.moveTo(x - x1, y + y1);
				ctx.lineTo(x - x1 - S10, y + y1 + S10);
				ctx.moveTo(x - x1 - S10, y + y1 + S10);
				ctx.lineTo(x - x1 - 3 * S10, y + y1 + S10);
				ctx.stroke();
				ctx.fillText(value, x - x1 - 3.5 * S10, y + y1 + S10);
			} else {
				ctx.textAlign = 'right';
				ctx.moveTo(x - x1, y - y1);
				ctx.lineTo(x - x1 - S10, y - y1 - S10);
				ctx.moveTo(x - x1 - S10, y - y1 - S10);
				ctx.lineTo(x - x1 - 3 * S10, y - y1 - S10);
				ctx.stroke();
				ctx.fillText(value, x - x1 - 3.5 * S10, y - y1 - S10);
			}
		}
	}

	// 绘制图表背景
	drawBackground() {
		this.ctx.fillStyle = this.bgColor;
		this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
		this.drawTitle();
	}

	// 绘制图表标题
	drawTitle() {
		let title = this.title;
		if (!title.text) {
			return;
		}
		let ctx = this.ctx;
		ctx.beginPath();
		ctx.font = title.font;
		ctx.textAlign = 'center';
		ctx.fillStyle = title.color;
		if (title.position === 'top') {
			ctx.textBaseline = 'top';
			ctx.fillText(title.text, this.canvas.width / 2, title.top);
		} else {
			ctx.textBaseline = 'bottom';
			ctx.fillText(title.text, this.canvas.width / 2, this.canvas.height - title.bottom);
		}
	}

	// 绘制X轴
	drawXAxis() {
		let ctx = this.ctx;
		let y = this.canvas.height - this.bottomPadding + 0.5;
		// x轴坐标点
		ctx.beginPath();
		ctx.strokeStyle = this.axisColor;
		ctx.moveTo(this.leftPadding, y);
		ctx.lineTo(this.canvas.width - this.rightPadding, y);
		ctx.stroke();
		this.drawXPoint();
	}

	// 绘制X轴坐标点
	drawXPoint() {
		let ctx = this.ctx;
		ctx.beginPath();
		ctx.font = 12 * DPI + 'px Microsoft YaHei';
		ctx.textAlign = this.xRorate ? 'right' : 'center';
		ctx.textBaseline = 'top';
		ctx.fillStyle = this.axisColor;
		for (let i = 0; i < this.labels.length; i++) {
			let text = this.labels[i];
			let x = this.leftPadding + this.xLength * (i + 1) + 0.5;
			let y = this.canvas.height - this.bottomPadding;
			if (this.showGrid) {
				// 绘制网格线
				ctx.strokeStyle = this.gridColor;
				ctx.moveTo(x, y);
				ctx.lineTo(x, this.topPadding + S10);
			} else {
				ctx.moveTo(x, y);
				ctx.lineTo(x, y - S5);
			}
			ctx.stroke();
			ctx.save();
			// 允许文本旋转
			ctx.translate(x - this.xLength / 2, y + S5);
			ctx.rotate(-this.xRorate * Math.PI / 180);
			ctx.fillText(text, 0, 0);
			ctx.restore();
		}
	}

	// 绘制Y轴
	drawYAxis() {
		let ctx = this.ctx;
		ctx.beginPath();
		ctx.strokeStyle = this.axisColor;
		ctx.moveTo(this.leftPadding - 0.5, this.canvas.height - this.bottomPadding + 0.5);
		ctx.lineTo(this.leftPadding - 0.5, this.topPadding + 0.5);
		ctx.stroke();
		this.drawYPoint();
	}

	// 绘制Y轴坐标点
	drawYPoint() {
		let ctx = this.ctx;
		ctx.font = 12 * DPI + 'px Microsoft YaHei';
		ctx.textAlign = 'right';
		ctx.textBaseline = 'middle';
		ctx.beginPath();
		for (let i = 0; i < this.yEqual; i++) {
			let x = this.leftPadding;
			let y = this.canvas.height - this.bottomPadding - this.yLength * (i + 1) + 0.5;
			if (this.showGrid) {
				// 绘制网格线
				ctx.strokeStyle = this.gridColor;
				ctx.moveTo(x, y);
				ctx.lineTo(this.canvas.width - this.rightPadding - S10, y);
			} else {
				ctx.strokeStyle = this.axisColor;
				ctx.moveTo(x - S5, y);
				ctx.lineTo(x, y);
			}
			ctx.stroke();
			ctx.save();
			ctx.fillStyle = this.axisColor;
			// 文本旋转
			ctx.translate(x - S10, y);
			ctx.rotate(-this.yRorate * Math.PI / 180);
			ctx.fillText(this.ySpace * (i + 1), 0, 0);
			ctx.restore();
		}
	}

	// 绘制图例
	drawLegend() {
		let legend = this.legend;
		// 是否显示图例
		if (legend.display) {
			let ctx = this.ctx;
			let pie = this.type === 'pie' || this.type === 'ring';
			ctx.beginPath();
			ctx.font = legend.font;
			ctx.textAlign = 'left';
			ctx.textBaseline = 'middle';

			let length = pie ? this.labels.length : this.datasets.length;
			let x = (this.canvas.width - (this.legend.textWidth + (5 * length - 2) * S10)) / 2;
			let textWidth = 0;

			for (let i = 0; i < length; i++) {
				const item = pie ? this.datasets[0] : this.datasets[i];
				const text = (pie ? this.labels[i] : item.label) || '';
				ctx.fillStyle = (item.colorList && item.colorList[i]) || item.fillColor || this.colorList[i];
				// 区分图例位置显示，分别为top,bottom,left
				if (legend.position === 'top') {
					this.drawLegendIcon(x + (5 * S10 * i) + textWidth, legend.top - S5, 2 * S10, S10);
					ctx.fillStyle = legend.color;
					ctx.fillText(text, x + (5 * i + 3) * S10 + textWidth, legend.top);
				} else if (legend.position === 'bottom') {
					this.drawLegendIcon(x + (5 * S10 * i) + textWidth, this.canvas.height - legend.bottom - S5, 2 * S10, S10);
					ctx.fillStyle = legend.color;
					ctx.fillText(text, x + (5 * i + 3) * S10 + textWidth, this.canvas.height - legend.bottom);
				} else {
					ctx.fillRect(S10, legend.top + 2 * S10 * i, 2 * S10, S10);
					ctx.fillStyle = legend.color;
					ctx.fillText(text, 4 * S10, legend.top + 2 * S10 * i + 0.5 * S10);
				}
				textWidth += Math.ceil(ctx.measureText(text).width);
			}
		}
	}

	// 绘制图例每项里的小图标，折线图为线条，其他为矩形
	drawLegendIcon(x, y, w, h) {
		let ctx = this.ctx;
		if (this.type === 'line') {
			ctx.beginPath();
			ctx.strokeStyle = ctx.fillStyle;
			ctx.lineWidth = 2 * DPI;
			ctx.moveTo(x, y + S5);
			ctx.lineTo(x + 2 * S10, y + S5);
			ctx.stroke();
			ctx.lineWidth = 1 * DPI;
			ctx.arc(x + S10, y + S5, 3 * DPI, 0, 2 * Math.PI, true);
			ctx.fill();
		} else {
			ctx.fillRect(x, y, w, h);
		}
	}
}

export default Schart;
